﻿using AiChiTu.TraceabilitySystem.Domain.ConfigEntities;
using AiChiTu.TraceabilitySystem.Domain.RBAC;
using AiChiTu.TraceabilitySystem.ErrorCode;
using AiChiTu.TraceabilitySystem.ErrorCode.Extensions;
using AiChiTu.TraceabilitySystem.Infrastructure.Interfaces;
using AiChiTu.TraceabilitySystem.Read.API.Applications.Commands.Logins;
using AiChiTu.TraceabilitySystem.Read.API.Dtos.Logins;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace AiChiTu.TraceabilitySystem.Read.API.Applications.CommandsHandlers.Logins
{
	/// <summary>
	/// 登录请求命令处理
	/// </summary>
	public class LoginCommandHandle : IRequestHandler<LoginCommand, APIResult<LoginDTO>>
	{
		private readonly IBaseRepository<UserInfo> userRepository;
		private readonly IBaseRepository<UserRole> userroleRepository;
		private readonly IBaseRepository<Role> roleRepository;
		private readonly IBaseRepository<RolePermission> rolepermissionRepository;
		private readonly IBaseRepository<Permission> permissionRepository;
		private readonly IBaseRepository<PermissionButton> permissionbuttonRepository;
		private readonly IBaseRepository<ButtonInfo> buttonRepository;
		private readonly IOptions<JwtConfig> jwtConfig;

		public LoginCommandHandle(IBaseRepository<UserInfo> userRepository, IBaseRepository<UserRole> userroleRepository, IBaseRepository<Role> roleRepository, IBaseRepository<RolePermission> rolepermissionRepository, IBaseRepository<Permission> permissionRepository, IBaseRepository<PermissionButton> permissionbuttonRepository, IBaseRepository<ButtonInfo> buttonRepository, IOptions<JwtConfig> jwtConfig)
		{
			this.userRepository = userRepository;
			this.userroleRepository = userroleRepository;
			this.roleRepository = roleRepository;
			this.rolepermissionRepository = rolepermissionRepository;
			this.permissionRepository = permissionRepository;
			this.permissionbuttonRepository = permissionbuttonRepository;
			this.buttonRepository = buttonRepository;
			this.jwtConfig = jwtConfig;
		}
		/// <summary>
		/// 登录请求命令处理
		/// </summary>
		/// <param name="request">登录请求命令</param>
		/// <param name="cancellationToken">取消</param>
		/// <returns>返回任务</returns>
		public async Task<APIResult<LoginDTO>> Handle(LoginCommand request, CancellationToken cancellationToken)
		{
			APIResult<LoginDTO> result = new APIResult<LoginDTO>();
			result.Code = ResultCode.LoginFailed;
			result.Message = ResultCode.LoginFailed.GetDescription();

			if (string.IsNullOrEmpty(request.UserInfoName) || string.IsNullOrEmpty(request.UserInfoPassword))
			{
				result.Message += " , 用户名或密码不能为空!";
				return await Task.FromResult(result);
			}
			request.UserInfoPassword = request.UserInfoPassword.GetMD5Password();// 使用MD5技术加密字符串

			UserInfo? userInfo = userRepository.QueryAllAsync(x => x.UserInfoName == request.UserInfoName).FirstOrDefault();
			if (userInfo == null)
			{
				result.Message += " , 用户名不存在!";
				return await Task.FromResult(result);
			}
			if (request.UserInfoPassword != userInfo.UserInfoPassword)
			{
				result.Message += " , 用户名和密码不匹配!";
				return await Task.FromResult(result);
			}
			LoginDTO loginDTO = new LoginDTO()
			{
				UserInfoId = userInfo.UserInfoId,
				UserInfoName = userInfo.UserInfoName,
				Token = "Bearer " + CreateTokenString(userInfo.UserInfoId),
				UserInfoNickname = userInfo.UserInfoNickname,

			};
			result.Data = loginDTO;

			result.Code = ResultCode.LoginSuccess;
			result.Message = ResultCode.LoginSuccess.GetDescription();
			return await Task.FromResult(result);
		}
		/// <summary>
		/// 生成 JWT Token（令牌）
		/// </summary>
		/// <returns>返回token字符串</returns>
		private string CreateTokenString(int UserInfoId)
		{
			//私钥
			var secretByte = Encoding.UTF8.GetBytes(jwtConfig.Value.Secret);
			// 非对称加密
			var signingKey = new SymmetricSecurityKey(secretByte);
			// 使用256 生成数字签名
			var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

			// 在 C# 中，List<T> 是一个泛型列表类，它位于 System.Collections.Generic 命名空间下。Claim 类通常来自于System.Security.Claims 命名空间，用于表示与身份验证和授权相关的声明。
			// 声明存储一个变量用于存储登录人ID
			// claims 存储的数据只能是字符串
			List<Claim> claims = new List<Claim>();
			claims.Add(new Claim("UserInfoId", UserInfoId.ToString()));

			// 生成Token
			var token = new JwtSecurityToken(
				issuer: jwtConfig.Value.Issuer,
				audience: jwtConfig.Value.Audience,

				// 使用token携带自定义数据
				claims: claims,

				expires: DateTime.Now.AddDays(1), // 一天后过期
				signingCredentials: signingCredentials
			);
			// 生成token 字符串
			var strToken = new JwtSecurityTokenHandler().WriteToken(token);
			return strToken;
		}
	}
}
